import sys
from tkinter import filedialog
import click
from rich.console import Console
from rich.table import Table
import os
import readchar
import signal
import shutil
import tkinter as tk


class XFileSelector:
    def __init__(self, start_dir=".", select_file=True, is_multi_file=False):
        """
        :param start_dir: 初始路径
        :param select_file: True文件False目录
        :param is_multi_file: 当select_file==true，is_multi_file控制是否多选；目录只能单选
        """
        self.is_multi_file = is_multi_file
        self.select_file = select_file
        self.console = Console()
        self.current_dir = os.path.abspath(start_dir)
        self.items = []
        self.selected = set()
        self.cursor = 0
        self.view_offset = 0
        self.page_size = max(10, shutil.get_terminal_size().lines - 8)
        signal.signal(signal.SIGWINCH, self.handle_resize)

    def handle_resize(self, signum, frame):
        self.page_size = max(10, shutil.get_terminal_size().lines - 8)

    def load_items(self):
        self.items = [".."]
        try:
            items = sorted(os.listdir(self.current_dir))
            self.items += items
        except Exception as e:
            self.console.print(f"[red]Error: {e}[/red]")

    def render(self):
        self.console.clear()
        table = Table(show_header=True, header_style="bold cyan")
        table.add_column("索引", width=4)
        table.add_column("类型", width=5)
        table.add_column("名称", overflow="fold", ratio=1, no_wrap=False)
        table.add_column("状态", width=5)
        start = self.view_offset
        end = start + self.page_size
        for idx, item in enumerate(self.items[start:end], start=start):
            fpath = os.path.join(self.current_dir, item)
            ftype = "目录" if os.path.isdir(fpath) else "文件"
            sel = "选中" if fpath in self.selected else ""
            select_current = True if idx == self.cursor else False
            start_style = "[bold magenta]" if select_current else ""
            end_style = "[/bold magenta]" if select_current else ""
            table.add_row(f"{start_style}{idx}{end_style}", f"{start_style}{ftype}{end_style}",
                          f"{start_style}{item}{end_style}", f"{start_style}{sel}{end_style}")
        self.console.print(f"[bold cyan]{self.current_dir}[/bold cyan]", f"{len(self.items) - 1}个项目")
        self.console.print(table)
        can_move = len(self.items) != 1
        current_is_dir = os.path.isdir(os.path.join(self.current_dir, self.items[self.cursor]))
        can_select = not current_is_dir
        can_remove = not len(self.selected) == 0
        self.console.print(
            f"{'[red]' if can_move else ''}↑↓:移动{'[/red]' if can_move else ''}", "|",
            f"{'[red]' if can_select else ''}空格:选择{'[/red]' if can_select else ''}", "|",
            f"{'[red]' if current_is_dir else ''}Enter:进入{'[/red]' if current_is_dir else ''}", "|",
            f"{'[red]' if can_remove else ''}r:清除选中{'[/red]' if can_remove else ''}", "|",
            f"[red]q:退出[/red]", "|",
            f"[red]y或光标在 {'文件' if self.select_file else '文件夹'} 上按enter:选择完毕[/red]", "|",
            f"[red]a:当前目录全选[/red]", "|",
            f"[red]c:当前目录取消全选[/red]", "|",
            f"已选:{len(self.selected)}")

    def move_cursor(self, delta):
        new_cursor = self.cursor + delta
        if 0 <= new_cursor < len(self.items):
            self.cursor = new_cursor
            if self.cursor < self.view_offset:
                self.view_offset = self.cursor
            elif self.cursor >= self.view_offset + self.page_size:
                self.view_offset = self.cursor - self.page_size + 1

    def toggle_select(self):
        item = self.items[self.cursor]
        fpath = os.path.join(self.current_dir, item)
        if self.select_file:
            if os.path.isfile(fpath):
                if self.is_multi_file:
                    if fpath in self.selected:
                        self.selected.remove(fpath)
                    else:
                        self.selected.add(fpath)
                else:
                    if fpath in self.selected:
                        self.selected.remove(fpath)
                    else:
                        self.selected.clear()
                        self.selected.add(fpath)
        else:
            if not os.path.isfile(fpath):
                self.selected.clear()
                self.selected.add(fpath)

    def run(self):
        self.load_items()
        while True:
            self.render()
            key = readchar.readkey()
            if key == readchar.key.UP:
                self.move_cursor(-1)
            elif key == readchar.key.DOWN:
                self.move_cursor(1)
            elif key == readchar.key.SPACE:
                self.toggle_select()
            elif key == readchar.key.ENTER:
                item = self.items[self.cursor]
                if item == "..":
                    parent = os.path.dirname(self.current_dir)
                    if parent != self.current_dir:
                        self.current_dir = parent
                        self.cursor = 0
                        self.view_offset = 0
                        self.load_items()
                else:
                    fpath = os.path.join(self.current_dir, item)
                    if os.path.isdir(fpath):
                        self.current_dir = fpath
                        self.cursor = 0
                        self.view_offset = 0
                        self.load_items()
                        if not self.select_file:
                            self.console.clear()
                            return list(self.selected)
                    else:
                        # 是文件
                        if self.select_file:
                            self.console.clear()
                            return list(self.selected)
            elif key == "r":
                self.cursor = 0
                self.selected.clear()
            elif key == "q":
                self.console.clear()
                return None
            elif key == "y":
                self.console.clear()
                return list(self.selected)
            elif key == "t":
                self.cursor = 0
                self.view_offset = 0
            elif key == 'b':
                self.cursor = len(self.items) - 1
                self.view_offset = self.cursor - self.page_size + 1
            elif key == 'a':
                self.selected.clear()
                for item in self.items:
                    fpath = os.path.join(self.current_dir, item)
                    if os.path.isdir(fpath) != self.select_file:
                        self.selected.add(fpath)
            elif key == 'c':
                for item in self.items:
                    fpath = os.path.join(self.current_dir, item)
                    if os.path.isdir(fpath) != self.select_file:
                        self.selected.remove(fpath)
            else:
                self.console.clear()
                return None

    def select_files_gui(self, start_dir="."):
        try:
            root = tk.Tk()
            root.withdraw()
            if self.select_file:
                if self.is_multi_file:
                    files = filedialog.askopenfilenames(
                        initialdir=start_dir,
                        title="选择多个文件"
                    )
                    root.destroy()
                    return list(files) if files else []
                else:
                    files = filedialog.askopenfilename(
                        initialdir=start_dir,
                        title="选择文件"
                    )
                    root.destroy()
                    return None if files == "" else files
            else:
                files = filedialog.askdirectory(
                    initialdir=start_dir,
                    title="选择目录"
                )
                root.destroy()
                return files
        except Exception:
            click.echo("GUI not available, switching to terminal mode")
            return self.run()

    def select_files(self, start_dir="."):
        return self.run() if sys.stdin.isatty() and sys.stdout.isatty() else self.select_files_gui(start_dir)

